iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 15
0
Software Development

認識scala系列 第 15

Scala day 15 (traits & abstract class)

  • 分享至 

  • xImage
  •  

traits VS abstract class

  • 抽象類別跟 trait 其實很像,跟 trait 還是有一些差異 :

抽象類別只能被單一繼承,trait 可以被單一繼承又可以 with 多個

scala> abstract class A
defined class A

scala> abstract class B
defined class B

scala> class C extends A
defined class C


scala> trait A
defined trait A

scala> trait B
defined trait B

scala> class C extends A with B
defined class C
  • 記得使用 with trait 要先 extends 才可以
scala> class C with A with B
<console>:1: error: ';' expected but 'with' found.
       class C with A with B
               ^

抽象類別的 constructor 可有參數,trait 不能定義有參數的 constructor

cala> abstract class Employee(id:String,name:String)
defined class Employee

scala> trait Employee(id:String,name:String)
<console>:1: error: traits or objects may not have parameters
       trait Employee(id:String,name:String)
                     ^

抽象類別的 super VS trait 的 super

  • 抽象類別的super是靜態呼叫父類別的方法,trait 是由於可以 with 多個所以 super 是動態的無法知道是哪個父類別,只有在建立類別時才會知道.

抽象類別的 super :

scala> abstract class Counter {
     |  def count(num1: Int , num2: Int) : Unit
     | }
defined class Counter

scala> class MyCounter extends Counter {
     |  var sum = 0
     |  def count(num1: Int , num2: Int): Unit = sum = num1 + num2
     |  def getSum = sum
     | }
defined class MyCounter

trait 的 super 由於是動態的所以 with 的順序不同會影響 super 最後的結果,所以又稱 stackable modifications (堆疊修飾) :

scala> abstract class Counter {
     |   def count(num1: Int , num2: Int) : Unit
     | }
defined class Counter

scala> class MyCounter extends Counter {
     |   var sum = 0
     |   def count(num1: Int , num2: Int): Unit = sum = num1 * num2
     |   def getSum = sum
     | }
defined class MyCounter

scala> trait Counter1 extends MyCounter {
     |   abstract override def count(num1:Int , num2:Int) = {
     |     if(num1 < 0 || num2 < 0) {
     |       super.count(num1,num2)
     |     } else {
     |       sum = num1 + num2
     |     }
     |   }
     | }
defined trait Counter1

scala> trait Filter1 extends MyCounter {
     |   abstract override def count(num1:Int , num2:Int) = {
     |     if(num1 < 0 || num2 < 0) {
     |       super.count(num1,num2)
     |     } else {
     |       sum = num1 + num2 * 2
     |     }
     |   }
     | }
defined trait Filter1

stackable modifications 會從最右邊開始,例如下面 coutner1 這個物件,
Filter1 的 super 會呼叫 Counter1 的 method ,Counter1 的 super 會呼叫 MyCounter 的 method :

scala> val counter1 = (new MyCounter with Counter1 with Filter1)
counter1: MyCounter with Counter1 with Filter1 = $anon$1@a5e8260

scala> counter1.count(1,2)
scala> counter1.sum
res1: Int = 5

scala> counter1.count(-2,5)
scala> counter1.sum
res3: Int = -10

counter2 這個物件,Counter1 的 super 會呼叫 Filter1 的 method ,Filter1 的 super 會呼叫 MyCounter 的 method :

scala> val counter2 = (new MyCounter with Filter1 with Counter1)
counter2: MyCounter with Filter1 with Counter1 = $anon$1@167bb934

scala> counter2.count(1,2)

scala> counter2.sum
res7: Int = 3

scala> counter2.count(-1,2)
scala> counter2.sum
res9: Int = -2

總結


  • 在 scala trait 的功能跟 abstract class 差不多,但我覺得 trait 可以多重繼承跟實作具體的方法就比 abstract class 好用很多了.感覺像是 java interface 的加強版.雖然抽象類別有建構子可以初始化參數,但其實 trait 也可以提供方法傳遞即可.scala 提供了許多 java 額外的東西,所以寫法更豐富,或許這也是其中一種理由讓它可以實作OOP(物件導向)也可以實作FP(函數式).

上一篇
Scala day 14 (traits)
下一篇
Scala day 16 (traits self type)
系列文
認識scala30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
kmtiger
iT邦新手 5 級 ‧ 2018-03-19 16:04:01

看了一半 先給作著一個讚

我要留言

立即登入留言